package com.dhz.common.solr;

import com.dhz.common.solr.server.HttpSolrClientFactory;
import com.dhz.common.solr.server.SolrClientFactory;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.SolrPingResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.util.*;

/**
 * Solr 访问/操作工具类；使用Lambda来编写部分代码，练手
 *
 * @author Fyduan
 */
public class SolrTemplate implements SolrOperations, InitializingBean {

    private static final Logger logger = LoggerFactory.getLogger(SolrTemplate.class);

    private String solrCore;

    private SolrClientFactory solrClientFactory;

    public SolrTemplate(SolrClientFactory solrClientFactory) {
        Assert.notNull(solrClientFactory, "SolrClientFactory不能为null");
        Assert.notNull(solrClientFactory.getSolrClient(), "SolrClientFactory必须能够取得一个SolrClient实例");

        this.solrClientFactory = solrClientFactory;
    }

    public SolrTemplate(SolrClient solrClient, String core) {
        this(new HttpSolrClientFactory(solrClient, core));
        this.solrCore = core;
    }

    public final SolrClient getSolrClient() {
        return solrClientFactory.getSolrClient(this.solrCore);
    }

    @Override
    public SolrPingResponse ping() {
        return execute(SolrClient::ping);
    }

    @Override
    public long count(final SolrQuery query) {
        Assert.notNull(query);

        return execute(solrClient -> {
            query.setStart(0);
            query.setRows(0);
            return solrClient.query(query).getResults().getNumFound();
        });
    }

    @Override
    public UpdateResponse saveDoc(SolrInputDocument doc) {
        return saveDoc(doc, -1);
    }

    @Override
    public UpdateResponse saveDoc(SolrInputDocument doc, int commitWithInMs) {
        return execute(solrClient -> {
            UpdateResponse response = solrClient.add(doc, commitWithInMs);
            solrClient.commit();
            return response;
        });
    }

    @Override
    public UpdateResponse saveDocs(Collection<SolrInputDocument> docs) {
        return saveDocs(docs, -1);
    }

    @Override
    public UpdateResponse saveDocs(Collection<SolrInputDocument> docs, int commitWithInMs) {
        return execute(solrClient -> {
            UpdateResponse response = solrClient.add(docs, commitWithInMs);
            solrClient.commit();
            return response;
        });
    }

    @Override
    public UpdateResponse delete(final SolrQuery query) {
        Assert.notNull(query, "过滤参数不能为空.");
        return execute(solrClient -> {
            UpdateResponse response = solrClient.deleteByQuery(query.getQuery());
            solrClient.commit();
            return response;
        });
    }

    @Override
    public UpdateResponse deleteById(final String id) {
        Assert.notNull(id, "Cannot delete 'null' id.");
        return execute(solrClient -> {
            UpdateResponse response = solrClient.deleteById(id);
            solrClient.commit();
            return response;
        });
    }

    @Override
    public UpdateResponse deleteById(final Collection<String> ids) {
        Assert.notNull(ids, "Cannot delete 'null' id collection.");
        final List<String> _ids = new ArrayList<String>(ids);
        return execute(solrClient -> {
            UpdateResponse response = solrClient.deleteById(_ids);
            solrClient.commit();
            return response;
        });
    }

    @Override
    public <T> T getById(Serializable id, Class<T> clazz) {
        Assert.notNull(id, "Id must not be null.");

        Collection<T> result = getById(Arrays.asList(id), clazz);
        if (result.isEmpty()) {
            return null;
        }

        return result.iterator().next();
    }

    @Override
    public <T> Collection<T> getById(final Collection<? extends Serializable> ids, final Class<T> clazz) {

        if (ids == null || ids.isEmpty()) {
            return Collections.emptyList();
        }

        return execute(solrClient -> {
            QueryResponse response = new SolrRealtimeGetRequest(ids).process(solrClient);
            return response.getBeans(clazz);
        });
    }

    @Override
    public <T> T queryForObject(final SolrQuery query, final Class<T> clazz) {
        return null;
    }

    @Override
    public SolrDocument queryForSolrDoc(final SolrQuery query) {
        Assert.notNull(query, "查询参数不能为null");

        QueryResponse response = executeSolrQuery(query);

        if (response.getResults().size() > 0) {
            if (response.getResults().size() > 1) {
                logger.warn("返回记录数大于 1 , 返回第一个结果.");
            }
            return response.getResults().get(0);
        }

        return null;
    }

    @Override
    public SolrDocumentList queryForSolrDocs(SolrQuery query) {
        Assert.notNull(query, "查询参数不能为null");

        QueryResponse response = executeSolrQuery(query);

        return response.getResults();
    }

    @Override
    public void commit() {

    }

    @Override
    public void softCommit() {

    }

    @Override
    public void rollback() {

    }


    /**
     * 执行方法封装
     * @param callback 回掉接口的方法实现
     * @param <T> 返回类型
     * @return 返回值
     */
    @Override
    public <T> T execute(SolrCallback<T> callback) {
        Assert.notNull(callback);

        SolrClient solrClient = this.getSolrClient();
        try {
            return callback.callback(solrClient);
        } catch (Exception e) {
            // 抛出一个异常
            throw new SolrException("Solr操作失败.", e);
        }
    }


    @Override
    public void afterPropertiesSet() throws Exception {

    }

    /**
     * 提交查询，并返回{@link QueryResponse} 对象
     * @param query {@link SolrQuery} 查询参数
     * @return 返回
     */
    private QueryResponse executeSolrQuery(final SolrQuery query) {
        // 打印调试参数
        logger.debug("提交的参数：{}", query.toString());

        return execute(solrClient -> solrClient.query(query));
    }

}
